<?php
/**
 * Обработчик ошибок.
 */
class ErrorController extends Zend_Controller_Action {

	const DEFAULT_LAYOUT = 'default';

    protected static $_httpVersion = '1.1';

    /**
     * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
     */
    protected static $_httpCodes = array(
        200         => 'OK',
        201         => 'Created',
        202         => 'Accepted',
        203         => 'Non-Authoritative Information',
        204         => 'No Content',
        205         => 'Reset Content',
        206         => 'Partial Content',

        300         => 'Multiple Choices',
        301         => 'Moved Permanently',
        302         => 'Found',
        303         => 'See Other',
        304         => 'Not Modified',
        305         => 'Use Proxy',
        307         => 'Temporary Redirect',

        400         => 'Bad Request',
        401         => 'Unauthorized',
        402         => 'Payment Required',
        403         => 'Forbidden',
        404         => 'Not Found',
        405         => 'Method Not Allowed',
        406         => 'Not Acceptable',
        407         => 'Proxy Authentication Required',
        408         => 'Request Timeout',
        409         => 'Conflict',
        410         => 'Gone',
        411         => 'Length Required',
        412         => 'Precondition Failed',
        413         => 'Request Entity Too Larged',
        414         => 'Request-URI Too Long',
        415         => 'Unsupported Media Type',
        416         => 'Requested Range Not Satisfiable',
        417         => 'Expectation Failed',

        500         => 'Internal Server Error',
        501         => 'Not Implemented',
        502         => 'Bad Gateway',
        503         => 'Service Unavailable',
        504         => 'Gateway Timeout',
        505         => 'HTTP Version Not Supported',

    );

    protected $_defaultErrorCode = 500;

	function errorAction() {

        $layout = Zend_Layout::getMvcInstance();

        // Объект ошибки
		$error = $this->_getParam('error_handler');

        // если не передан CODE и переданы коды по умолчанию
        $defaultErrorCode = $this->_getParam('default_error_code');
        if (!isInt($defaultErrorCode)) {
            $defaultErrorCode = $this->_defaultErrorCode;
        }

		//имя сегмента для вывода ошибки в layout
        $respSegment = $this->_getParam('error_resp_segment', 'exception');

        //имя скрипта с дизайном ошибки
        $viewScript = $this->_getParam('error_view_script');

        //layout для вывода ошибки
        $layoutScript = $this->_getParam('error_layout_script');

        //редиректы для указанных кодов ошибок (code => redirectParams)
        $redirects = $this->_getParam('redirects');

        //отправлять сообщение в JSON-формате при ошибке на ajax-запрос
        $jsonMessage = $this->_getParam('json_message');

        $debugMode = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getOption('debug_mode');

        // показывать исходное сообщение об ошибке, если для него нет перевода
        $showOriginalMessage = $this->_getParam('show_original_message');
        if (!$showOriginalMessage) {
            $showOriginalMessage = $debugMode ? true : false;
        }

        $xhr = $this->getRequest()->isXmlHttpRequest();

        // Сообщение об ошибке
		$message = $error->exception->getMessage();

        // Заголовок ошибки
        $caption = null;

		if ($debugMode) {
            if (method_exists($error->exception, 'getPrevious')) {
                $e = $error->exception;
                while ($e = $e->getPrevious()) {
                    $message .= "\n {$e->getTraceAsString()}";
                }
            }
			$message .= "\n {$error->exception->getTraceAsString()}";
		}

        // Код ошибки
        $code = (int)$error->exception->getCode();

        $checkError = isset(self::$_httpCodes[$code]);

        // Внутренние ошибки приложения
        if ( !$checkError ) {
            switch($error->type) {
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
                    $code = 404;
                break;

                default:
                    $code = $defaultErrorCode;
            }
        }

        $this->getResponse()->setRawHeader('HTTP/'.self::$_httpVersion . ' ' . $code . ' ' . self::$_httpCodes[$code]);

        if (is_array($redirects)) {
            if (isset($redirects[$code])) {

                $redirects[$code]['params']['backurl'] = $error->request->getRequestUri();

                $url = $this->_helper->url($redirects[$code]);

                $this->_redirect($url);
                return;
            }
        }

        //перевод сообщения об ошибке
        $translated = false;

        if (!$debugMode && Zend_Registry::isRegistered('Zend_Translate')) {

            try {
                $locale = Zend_Locale::findLocale(null);

                $content = $this->_helper->moduleConfig->getConfig(implode(DIRECTORY_SEPARATOR, array(
                    'lang', $locale, 'controllers',
                    $this->_request->getControllerName('controller'),
                )));

                $translate = Zend_Registry::get('Zend_Translate');
                $translate->addTranslation(array('content' => $content));

                //перевод по тексту сообщения
                $tm = $translate->translate($message);
                if ($tm != $message) {
                    $message = $tm;
                    $translated = true;
                }

                //перевод по коду ошибки
                if (!$translated) {
                    $tcode = 'error'.$code;
                    $tm = $translate->translate($tcode);
                    if ($tm != $tcode) {
                        $message = $tm;
                        $translated = true;
                    }
                }

                //заголовок ошибки (если есть)
                if (!$caption) {
                    $tcode = 'caption'.$code;
                    $tm = $translate->translate($tcode);
                    if ($tm != $tcode) {
                       $caption = $tm;
                    }
                }
                
            } catch (Exception $e) {}
        }

        if (!$translated && !$showOriginalMessage) {
            $tm = $translate->translate('default');
            if ($tm != $message) {
                $message = $tm;
            } else {
                $message = '';
            }
        }

        //ответ на ajax запрос
        if ($xhr) {

            $this->_helper->viewRenderer->setNoRender(true);

            $cnt = 2;
            
            while ($cnt-- > 0) {
                try {
                    $this->getResponse()->setHttpResponseCode($code);
                    break;
                } catch (Zend_Exception $e) {
                    $code = $defaultErrorCode;
                }
            }

            /*
             * отправка json объекта
             * {
             *      message: "Текст сообщения об ошибке",
             *      debugMode: bool,
             *      caption: "Заголовок (если не установлен, то null)"
             * }
             */
            if ($jsonMessage) {
                $jsonData = array(
                    'message' => $message,
                    'debugMode' => (int)$debugMode,
                    'caption' => $caption
                );

                echo Zend_Json::encode($jsonData);
            }

            return;

        }

        //вывод ошибки в layout
        if ($layout && $layoutScript) {
            $layout->setLayout($layoutScript);
        }

        //вывод ошибки в именованный сегмент 
        if ($respSegment && Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {
            $this->_helper->viewRenderer->setResponseSegment($respSegment);
        }

        $this->view->message = $message;
        $this->view->code = $code;
        $this->view->caption = $caption;
        $this->view->debugMode = $debugMode;

        //если установлен шаблон для вывода ошибки, иначе используется error.phtml
        if ($viewScript) {
            $this->render($viewScript);
        }

	}
}